import SparkMD5 from 'spark-md5';
import { Chunk } from './typing';

// 格式化文件大小
export const formatFileSize = (bytes: number): string => {
  if (bytes === 0) return '0 Bytes';
  const k = 1024;
  const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];
  const i = Math.floor(Math.log(bytes) / Math.log(k));
  return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
};
// 格式化上传速度
export const formatSpeed = (bytesPerSecond: number): string => {
  if (bytesPerSecond === 0) return '0 B/s';
  const k = 1024;
  const sizes = ['B/s', 'KB/s', 'MB/s', 'GB/s'];
  const i = Math.floor(Math.log(bytesPerSecond) / Math.log(k));
  return parseFloat((bytesPerSecond / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
};
// 计算文件哈希值
export const calculateFileHash = async (file: File): Promise<string> => {
  return new Promise((resolve, reject) => {
    const spark = new SparkMD5.ArrayBuffer();
    const fileReader = new FileReader();
    const chunkSize = 2 * 1024 * 1024; // 2MB
    const totalChunks = Math.ceil(file.size / chunkSize);
    let currentChunk = 0;

    const loadNext = () => {
      const start = currentChunk * chunkSize;
      const end = Math.min(start + chunkSize, file.size);
      fileReader.readAsArrayBuffer(file.slice(start, end));
    };

    fileReader.onload = ({ target }: ProgressEvent<FileReader>) => {
      if (!target?.result) {
        reject(new Error('读取文件失败'));
        return;
      }

      spark.append(target.result as ArrayBuffer);
      currentChunk++;

      if (currentChunk < totalChunks) {
        loadNext();
      } else {
        const hash = spark.end();
        resolve(hash);
        // createMessage.destroy();
      }
    };

    fileReader.onerror = () => {
      reject(new Error('计算文件哈希失败'));
    };

    loadNext();
  });
};

// 创建文件分片
export const createChunks = (file: File, propChunkSize: number): Chunk[] => {
  const chunkSize = propChunkSize * 1024 * 1024; // MB转字节
  const totalChunks = Math.ceil(file.size / chunkSize);
  const chunks: Chunk[] = [];

  for (let i = 0; i < totalChunks; i += 1) {
    const start = i * chunkSize;
    const end = Math.min(start + chunkSize, file.size);

    chunks.push({
      index: i,
      chunk: file.slice(start, end),
      size: end - start,
      total: totalChunks,
      uploaded: false,
      retryCount: 0,
    });
  }

  return chunks;
};

type PlainObject = { [key: string]: any };

export const objectToFormData = (obj: PlainObject, formData = new FormData(), parentKey?: string): FormData => {
  if (obj === null || obj === undefined) {
    return formData;
  }

  if (Array.isArray(obj)) {
    obj.forEach((value, index) => {
      const key = parentKey ? `${parentKey}[${index}]` : `[${index}]`;
      objectToFormData(value, formData, key);
    });
  } else if (typeof obj === 'object' && !(obj instanceof File)) {
    Object.entries(obj).forEach(([key, value]) => {
      const newKey = parentKey ? `${parentKey}[${key}]` : key;
      objectToFormData(value, formData, newKey);
    });
  } else {
    if (parentKey) {
      formData.append(parentKey, obj as string | Blob);
    }
  }

  return formData;
};
